#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "pd_linux.h"
#include "../scsi.h"
#include "xscsilibusb.h"



#ifndef UCHAR
    #define UCHAR unsigned char
#endif
#define INQUIRY_LENGTH  0x24

int gsleepTime = 1;


int scsiParse(unsigned char *dataBuf)
{
    if(dataBuf[0] == (unsigned char)0x55 && dataBuf[1] == (unsigned char)0x53 && dataBuf[2] == (unsigned char)0x42 && dataBuf[3] == (unsigned char)0x53)
        if(dataBuf[4] == (unsigned char)0x04 && dataBuf[5] == (unsigned char)0x83 && dataBuf[6] == (unsigned char)0x57 && dataBuf[7] == (unsigned char)0x20)
        {
            return dataBuf[12];
        }
    return -1;
}


int sentData(void *hDevice, unsigned char *buffer, int nBufferLen, int timeOut)
{
    int transferred = 0;
    int ret = x_scsi_libusb_transferwrite(hDevice, buffer, nBufferLen, &transferred,  timeOut);
    if(ret < 0)
    {
        return ret;
    }
    return transferred;
}

int receiveData(void *hDevice, unsigned char *buffer, int nBufferLen, int timeOut)
{
#ifndef __ANDROID__
    int transferred = 0;
    int ret = x_scsi_libusb_transferread(hDevice, buffer, nBufferLen, &transferred, timeOut);
    if(transferred <= 0)
    {
        return ret;
    }
    return transferred;
#else
    int transferred = 0;
    int ret = 0;
    int packetSize = MAX_ANDROID_PACKET_SIZE;
    int remindSize = 0;
    int readedSize = 0;
    int timeoutReset = timeOut;
    unsigned char *pRecvBuffer = new unsigned char[MAX_ANDROID_PACKET_SIZE];
    while((remindSize = (nBufferLen - readedSize)) > 0)
    {
        if(remindSize < MAX_ANDROID_PACKET_SIZE)
        {
            packetSize = MAX_ANDROID_SMALL_PACKET_SIZE;
        }
        if(remindSize < MAX_ANDROID_SMALL_PACKET_SIZE)
        {
            packetSize = remindSize;
        }
        transferred = 0;
        ret = x_scsi_libusb_transferread(hDevice, pRecvBuffer,  packetSize, &transferred, timeoutReset);
        if(ret < 0 || transferred <= 0)
        {
            break;
        }
        ret = transferred;
        if(ret >= remindSize)
        {
            memcpy(buffer + readedSize, pRecvBuffer, remindSize);
            readedSize += remindSize;

            break;
        }
        memcpy(buffer + readedSize, pRecvBuffer, ret);
        readedSize += ret;

        if(ret < packetSize)
        {
            break;
        }
    }
    delete[] pRecvBuffer;
    return readedSize;
#endif
}

BOOL Scsi_Transmit(void *hDevice, unsigned char *cdb, unsigned int cdbSize, unsigned char DataIn, unsigned char *DataBuffer, int DataTransferLength, int timeOut)
{
    unsigned char w_abyTmp[31] = {0x0};
    unsigned char w_abyCSW[13] = {0x0};
    int ret = 0;
    BOOL w_bRet = FALSE;
    int nPacketLen = 512;
    //if (DataTransferLength > 512 || DataIn == 0)
    {
        nPacketLen = DataTransferLength;
    }
    w_abyTmp[0] = (unsigned char)0x55;  //SCSI head
    w_abyTmp[1] = (unsigned char)0x53;
    w_abyTmp[2] = (unsigned char)0x42;
    w_abyTmp[3] = (unsigned char)0x43;
    w_abyTmp[4] = (unsigned char)0x04;  //HOST Flags
    w_abyTmp[5] = (unsigned char)0x83;
    w_abyTmp[6] = (unsigned char)0x57;
    w_abyTmp[7] = (unsigned char)0x20;
    memcpy(w_abyTmp + 8, &nPacketLen, 4);
    //w_abyTmp[8] = (unsigned char)0x00;    //sent data length
    //w_abyTmp[9] = (unsigned char)0x02;
    //w_abyTmp[10] = (unsigned char)0x00;
    //w_abyTmp[11] = (unsigned char)0x00;
    w_abyTmp[12] = (unsigned char)((DataIn & 0x01) << 7); // cCBWFlags
    w_abyTmp[13] = (unsigned char)0x00;     // cCBWlun
    w_abyTmp[14] = (unsigned char)cdbSize;  // cCBWCBLength

    memcpy(w_abyTmp + 15, cdb, cdbSize);
    ret = sentData(hDevice, w_abyTmp, 31, timeOut);
    if(0 >= ret)
    {
        return FALSE;
    }
    Sleep(gsleepTime);
    if(DataIn == 0)
    {
        ret = sentData(hDevice, DataBuffer, DataTransferLength,  timeOut);
        if(0 >= ret)
        {
            return FALSE;
        }
        Sleep(gsleepTime);
        ret = receiveData(hDevice, w_abyCSW, 13, timeOut);
        if(0 < ret)
        {
            int res = scsiParse(w_abyCSW);
            if(res == 0x00)
            {
                w_bRet = TRUE;
            }
            else
            {
                w_bRet =  FALSE;
            }
        }
    }
    else
    {
        unsigned char *bufRecv = new unsigned char[nPacketLen + 1024];
        memset(bufRecv, 0x0, nPacketLen + 1024);
        ret = receiveData(hDevice, bufRecv, nPacketLen, timeOut);
        Sleep(1);
        ret = receiveData(hDevice, w_abyCSW, 13, timeOut);
        if(0 < ret)
        {
            memcpy(DataBuffer, bufRecv, DataTransferLength);
            //memcpy(w_abyCSW, bufRecv+nPacketLen, 13);
            int res = scsiParse(w_abyCSW);
            if(res == 0x00)
            {
                w_bRet = TRUE;
            }
            else
            {
                w_bRet = FALSE;
            }
        }
        delete[] bufRecv;
    }
    return w_bRet;
}

BOOL Scsi_Write(void *hDevice, unsigned char *DataBuffer, int DataTransferLength, int TimeOutValue)
{
    unsigned char cdb[16] = {0};
    int ret = 0;

    cdb[0] = 0xEF;
    cdb[1] = 0xFE;
    ret = Scsi_Transmit(hDevice, cdb, 16, 0, DataBuffer, DataTransferLength, TimeOutValue);
    return ret;
}

BOOL Scsi_Read(void *hDevice, unsigned char *DataBuffer, int DataTransferLength, int TimeOutValue)
{
    unsigned char cdb[16] = {0};
    int ret = 0;

    cdb[0] = 0xEF;
    cdb[1] = 0xFF;

    ret = Scsi_Transmit(hDevice, cdb, 16, 1, DataBuffer, DataTransferLength, TimeOutValue);
    return ret;
}

int Scsi_Inquiry(void *hDevice, unsigned char *buffer, int cbBuffer)
{
    unsigned char cdb[16] = {0};
    int ret = 0;
    memset(buffer, 0x0, cbBuffer);
    memset(cdb, 0x0, 16);
    cdb[0] = 0x12;
    cdb[4] = INQUIRY_LENGTH;

    ret = Scsi_Transmit(hDevice, cdb, 16, 1, buffer, INQUIRY_LENGTH, 1 * 1000);
    return ret;
}



